package com.cj.framework.util;

import android.util.Base64;
import android.util.Log;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 * Created by cj on 2016/5/27.
 * Email:781806481@qq.com
 */
public class RSAUtils {
    //关于RSA公钥，需要去掉头部和尾部，在每一行（不包括最后一行）加入"\r"表示换行
    //关于该工具类，需要先载入公钥即loadPublicKey方法，用于生成内部字段publicKey

    private static final String TAG="RSAUtils";
    private static final String TYPE="RSA";
    private static final String CIPHER_TYPE="RSA/ECB/PKCS1Padding";
    private static final String CHARSET="UTF-8";

    private static PublicKey publicKey=null;

    /**
     * func：加密内容
     * alg：
     * 1：生成加密工具，需要RSA/ECB/PKCS1Padding字段，方式为加密和密钥
     * 2：进行加密生成字节数组
     * 3：对字节数组进行解码，并转成字符串
     * @param data:需要加密的内容
     * @return 加密后的内容
     */
    public static String encryptWithRSA(String data){
        String result=null;

        if(publicKey==null){
            return null;
        }

        try {
            //处理加密工具对象
            Cipher cipher=Cipher.getInstance(CIPHER_TYPE);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            //加密字符串
            byte[] sourceBytes=data.getBytes(CHARSET);
            byte[] dstBytes=cipher.doFinal(sourceBytes);
            byte[] encodeBytes=Base64.encode(dstBytes,Base64.DEFAULT);
            result=new String(encodeBytes,CHARSET);

        } catch (Exception e) {
            Log.d(TAG,"encryptWidthRSA:\n"+"error");
        }

        return result;
    }

    /**
     * func:用公钥对加密内容进行解密
     * alg:
     * 1：对加解密工具对象创建和初始化
     *
     * 2:将加密内容解码为字节数组
     * 3：将字节数组转化成字节输入流
     *
     * 4：创建字节输出流
     *
     * 5：字节流读取到字节数组中进行解码
     * 6：将解码后的字节数组保存到输出流
     * 7：将输出流转化为字节数组，然后转为字符串
     * @param data
     * @return
     */
    public static String decryptWithRSA(String data){
        String result=null;
        if(publicKey==null){
            return result;
        }
        try {
            //加解密工具对象创建和初始化
            Cipher cipher=Cipher.getInstance(CIPHER_TYPE);
            cipher.init(Cipher.DECRYPT_MODE,publicKey);

//              另一种写法
            InputStream ins=new ByteArrayInputStream(Base64.decode(data,Base64.DEFAULT));
            ByteArrayOutputStream writer=new ByteArrayOutputStream();
            byte[] buffer=new byte[128];
            int len;
            while((len=ins.read(buffer))!=-1){
                byte[] block=null;
                if(buffer.length==len){
                    block=buffer;
                }else{
                    block=new byte[len];
                    for(int i=0;i<len;i++){
                        block[i]=buffer[i];
                    }
                }
                writer.write(cipher.doFinal(block));
            }

            //输入流
//            byte[] sourceBytes=Base64.decode(data,Base64.DEFAULT);
//            InputStream is=new ByteArrayInputStream(sourceBytes);
//
//            //输出流
//            ByteArrayOutputStream writer=new ByteArrayOutputStream();
//
//            //读取，解码，并放入输出流
//            byte[] buffer=new byte[128];
//            int len;
//            while((len=is.read(buffer))!=-1){
//                writer.write(cipher.doFinal(buffer,0,len));
//            }
            result=new String(writer.toByteArray(),CHARSET);
            result=parse(result);
        } catch (NoSuchAlgorithmException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"无此算法");
        } catch (NoSuchPaddingException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"当请求特定填充机制但该环境中未提供异常");
        } catch (InvalidKeyException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"无效的公钥");
        } catch (BadPaddingException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"明文已损坏");
        } catch (IllegalBlockSizeException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"明文长度非法");
        } catch (IOException e) {
            Log.d(TAG,"decryptWithRSA:\n"+"IOException");
        }
        return result;
    }

    /**
     * 从字符串中加载公钥
     * alg：
     * 1：将字符串解码成字节数组
     * 2：将字节数组作为参数制作密钥规格材料X509EncodedKeySpec
     * 3:获取密钥工厂实例
     * 4：密钥工厂制造公钥
     * @param publicKeyStr
     */
    public static void loadPublicKey(String publicKeyStr){
        try{
            byte[] buffer=Base64.decode(publicKeyStr,Base64.DEFAULT);
            X509EncodedKeySpec keySpec=new X509EncodedKeySpec(buffer);
            KeyFactory keyFactory=KeyFactory.getInstance(TYPE);
            publicKey=keyFactory.generatePublic(keySpec);
        }catch(NoSuchAlgorithmException e){
            Log.d(TAG,"loadPublicKey:\n"+"无此算法");
        }catch (InvalidKeySpecException e){
            Log.d(TAG,"loadPublicKey:\n"+"捕捉到异常--无效的公钥字符串");
        }catch(NullPointerException e){
            Log.d(TAG,"loadPublicKey:\n"+"公钥数据为空--nullPointException");
        }
    }

    private static String parse(String data){
        String result="";
        result=data.replace("\r","").replace("\n","").replace("\t","");
        return result;
    }
}
